\subsubsection{std::vector}
\myindex{\Cpp!STL!std::vector}

Мы бы назвали \TT{std::vector} \q{безопасной оболочкой} (wrapper) \ac{PODT} массива в Си.

Изнутри он очень похож на \TT{std::string} (\myref{std_string}):
он имеет указатель на выделенный буфер, указатель на конец массива и указатель на конец выделенного буфера.

Элементы массива просто лежат в памяти впритык друг к другу, так же, как и в обычном массиве (\myref{arrays}).
\myindex{\Cpp!C++11}
В C++11 появился метод \TT{.data()} возвращающий указатель на этот буфер, это похоже на \TT{.c\_str()} в \TT{std::string}.

Выделенный буфер в \glslink{heap}{куче} может быть больше чем сам массив.

Реализации MSVC и GCC почти одинаковые, отличаются только имена полей в структуре
\footnote
{внутренности GCC: \url{http://go.yurichev.com/17086}}, так что здесь один исходник работающий для обоих компиляторов.
И снова здесь Си-подобный код для вывода структуры \TT{std::vector}:

\lstinputlisting[style=customc]{\CURPATH/STL/vector/2_RU.cpp}

Примерный вывод программы скомпилированной в MSVC:

\lstinputlisting{\CURPATH/STL/vector/MSVC.txt}

Как можно заметить, выделенного буфера в самом начале функции \main пока нет.
После первого вызова \TT{push\_back()} буфер выделяется.
И далее, после каждого вызова \TT{push\_back()} 
и длина массива и вместимость буфера (\IT{capacity}) увеличиваются.
Но адрес буфера также меняется, потому что вызов функции \TT{push\_back()} перевыделяет буфер в \glslink{heap}{куче}
каждый раз.
Это дорогая операция, вот почему очень важно предсказать размер будущего массива и зарезервировать место для него
при помощи метода \TT{.reserve()}.
Самое последнее число --- это мусор: там нет элементов массива в этом месте, вот откуда это случайное число.
Это иллюстрация того факта что метод \TT{operator[]} в \TT{std::vector} не проверяет индекс на правильность.
Более медленный метод \TT{.at()} с другой стороны, проверяет, и подкидывает исключение \TT{std::out\_of\_range} 
в случае ошибки.

Давайте посмотрим код:

\lstinputlisting[caption=MSVC 2012 /GS- /Ob1,style=customasmx86]{\CURPATH/STL/vector/MSVC.asm}

Мы видим, как метод \TT{.at()} проверяет границы и подкидывает исключение в случае ошибки.
Число, которое выводит последний вызов \printf берется из памяти, без всяких
проверок.

Читатель может спросить, почему бы не использовать переменные \q{size} и \q{capacity}, 
как это сделано в \TT{std::string}.
Должно быть, это для более быстрой проверки границ.

\myindex{Inline code}
Код генерируемый GCC почти такой же, в целом, но метод \TT{.at()} вставлен прямо в код:

\lstinputlisting[caption=GCC 4.8.1 -fno-inline-small-functions -O1,style=customasmx86]{\CURPATH/STL/vector/GCC.asm}

Метод \TT{.reserve()} точно так же вставлен прямо в код \main.
Он вызывает \TT{new()} если буфер слишком мал для нового массива, вызывает \TT{memmove()} 
для копирования содержимого буфера,
и вызывает \TT{delete()} для освобождения старого буфера.

Посмотрим, что выводит программа будучи скомпилированная GCC:

\lstinputlisting{\CURPATH/STL/vector/GCC.txt}

Мы можем заметить, что буфер растет иначе чем в MSVC.

При помощи простых экспериментов становится ясно, что в реализации MSVC буфер увеличивается
на \textasciitilde{}50\% каждый раз,
когда он должен был увеличен,
а у GCC он увеличивается на 100\% каждый раз, т.е. удваивается.

